package com.bf.xpdd.util;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;

import sun.misc.BASE64Encoder;

import com.bf.xpdd.exception.EncryptException;

public class TaobaoEncrypt
{

	/** logger */
	private static final Logger log = Logger.getLogger(TaobaoEncrypt.class);

	private static final char[] DIGITS = { '0', '1', '2', '3', '4', '5', '6',
			'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

	/**
	 * 签名运算
	 * 
	 * @param parameter
	 * @param secret
	 * @return
	 * @throws EncryptException
	 * 
	 */
	public static String sign(String parameter, String secret)
			throws EncryptException
	{

		// 对参数+密钥做MD5运算
		MessageDigest md = null;
		try
		{
			md = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e)
		{
			log.error(e.getMessage(), e);
			throw new EncryptException(e);
		}
		byte[] digest = md.digest((parameter + secret).getBytes());

		// 对运算结果做BASE64运算并加密
		sun.misc.BASE64Encoder encode = new BASE64Encoder();
		return encode.encode(digest);
	}

	/**
	 * 验证签名
	 * 
	 * @param sign
	 * @param parameter
	 * @param secret
	 * @return
	 * @throws EncryptException
	 */
	public static boolean validateSign(String sign, String parameter,
			String secret) throws EncryptException
	{
		return sign != null && parameter != null && secret != null
				&& sign.equals(sign(parameter, secret));
		// 注意，这个parameter并不就是上面的top_paramater，而是指的待签名验证的参数，即上面的top_appkey+top_parameter+top_session
	}

	/**
	 * 把经过BASE64编码的字符串转换为Map对象
	 * 
	 * @param str
	 * @return
	 * @throws Exception
	 */
	private static Map<String, String> convertBase64StringtoMap(String str)
	{
		if (str == null)
			return null;
		String keyvalues = null;
		try
		{
			keyvalues = new String(Base64.decodeBase64(URLDecoder.decode(str,
					"utf-8").getBytes("utf-8")));
		} catch (UnsupportedEncodingException e)
		{
			e.printStackTrace();
		}
		String[] keyvalueArray = keyvalues.split("\\&");
		Map<String, String> map = new HashMap<String, String>();
		for (String keyvalue : keyvalueArray)
		{
			String[] s = keyvalue.split("\\=");
			if (s == null || s.length != 2)
				return null;
			map.put(s[0], s[1]);
		}
		return map;
	}

	/**
	 * 验证TOP回调地址的签名是否合法。要求所有参数均为已URL反编码的。
	 * 
	 * @param topParams
	 *            TOP私有参数（未经BASE64解密）
	 * @param topSession
	 *            TOP私有会话码
	 * @param topSign
	 *            TOP回调签名
	 * @param appKey
	 *            应用公钥
	 * @param appSecret
	 *            应用密钥
	 * @param appSecret
	 *            应用密钥
	 * @return 验证成功返回true，否则返回false
	 * @throws NoSuchAlgorithmException
	 * @throws IOException
	 */
	public static boolean verifyTopResponse(String topParams,
			String topSession, String topSign, String appKey, String appSecret)
			throws NoSuchAlgorithmException, IOException
	{
		StringBuilder result = new StringBuilder();
		MessageDigest md5 = MessageDigest.getInstance("MD5");
		result.append(appKey).append(topParams).append(topSession)
				.append(appSecret);
		byte[] bytes = md5.digest(result.toString().getBytes("UTF-8"));
		BASE64Encoder encoder = new BASE64Encoder();
		return encoder.encode(bytes).equals(topSign);
	}

	public static String ParametersName(String top_parameters)
	{
		String nick = null;
		Map<String, String> map = convertBase64StringtoMap(top_parameters);
		Iterator keyValuePairs = map.entrySet().iterator();
		for (int i = 0; i < map.size(); i++)
		{
			Map.Entry entry = (Map.Entry) keyValuePairs.next();
			Object key = entry.getKey();
			Object value = entry.getValue();
			if (key.equals("visitor_nick"))
			{
				nick = (String) value;
			}
		}
		return nick;
	}

	/**
	 * 对参数进行MD5
	 * 
	 * @param params
	 *            排好序的参数Map
	 * @param secret
	 *            应用的密钥
	 * @return MD5签名字符串
	 * @throws UnsupportedEncodingException
	 */
	public static String sign(final TreeMap<String, String> params,
			String secret) throws UnsupportedEncodingException
	{
		if (null == params || params.isEmpty())
		{
			return (String) null;
		}
		if (isBlank(secret))
		{
			return (String) null;
		}
		StringBuilder sb = new StringBuilder();
		sb.append(secret);
		for (Iterator<Entry<String, String>> it = params.entrySet().iterator(); it
				.hasNext();)
		{
			Entry<String, String> entry = it.next();
			sb.append(entry.getKey()).append(defaultString(entry.getValue()));
		}
		sb.append(secret);
		byte[] bytes = sb.toString().getBytes("UTF-8");
		return md5Hex(bytes).toUpperCase();
	}

	public static boolean isBlank(String str)
	{
		int strLen;
		if (str == null || (strLen = str.length()) == 0)
		{
			return true;
		}
		for (int i = 0; i < strLen; i++)
		{
			if ((Character.isWhitespace(str.charAt(i)) == false))
			{
				return false;
			}
		}
		return true;
	}

	public static String defaultString(String str)
	{
		return str == null ? "" : str;
	}

	private static String md5Hex(byte[] bytes)
	{
		return new String(encodeHex(getMd5Digest().digest(bytes)));
	}

	private static MessageDigest getMd5Digest()
	{
		try
		{
			return MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e)
		{
			throw new RuntimeException(e.getMessage());
		}
	}

	public static char[] encodeHex(byte[] data)
	{
		int l = data.length;
		char[] out = new char[l << 1];
		// two characters form the hex value.
		for (int i = 0, j = 0; i < l; i++)
		{
			out[j++] = DIGITS[(0xF0 & data[i]) >>> 4];
			out[j++] = DIGITS[0x0F & data[i]];
		}
		return out;
	}
}
